package com.nulldev.util.graphics.renderIt.renderer.swing.smoothCanvas.demo;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JFrame;

import com.nulldev.util.graphics.renderIt.renderer.swing.smoothCanvas.CanvasFrameCallback;
import com.nulldev.util.graphics.renderIt.renderer.swing.smoothCanvas.RenderMethod;
import com.nulldev.util.graphics.renderIt.renderer.swing.smoothCanvas.SmoothCanvas;
import com.nulldev.util.graphics.renderIt.renderer.swing.smoothCanvas.SyncMethod;
import com.nulldev.util.gui.fontAPI.FontManager;
import com.nulldev.util.gui.swingAPI.Swing;
import com.nulldev.util.manage.legacy.FPSCounter;

public class SmoothCanvasTri extends SmoothCanvas implements CanvasFrameCallback {

	private static final long serialVersionUID = 1L;

	final int x[] =
		{ 100, 70, 130 };
	final int y[] =
		{ 50, 100, 100 };

	public SmoothCanvasTri() {
		super(RenderMethod.REPAINT);
		super.setRenderCallback(this);
		this.setSyncMethod(SyncMethod.SLEEP_TO_REFRESH);
		super.setClearOnFrameStart(false);
	}

	private double vertex[][][][] =
		{
				{
						{
								{ -1, -1, -1 },
								{ 1, -1, -1 } },
						{
								{ -1, 1, -1 },
								{ 1, 1, -1 } } },
				{
						{
								{ -1, -1, 1 },
								{ 1, -1, 1 } },
						{
								{ -1, 1, 1 },
								{ 1, 1, 1 } } } };

	// rotations in radians
	private double xyR = 0.005, xzR = 0.005, yzR = 0.005;

	// view attributes
	private int SCALE = 200, OFFSET = 350, DIAMETER = 12;
	private final FPSCounter fpsc = new FPSCounter();
	private static final Font f = FontManager.gets("Roboto", "Product Sans", "SF Pro Display", "Arial").getFont(12);

	@Override
	public void onFrame(Graphics g) {
		g.setFont(f);
		// rotate cube
		for (int x = 0; x < 2; x++) {
			for (int y = 0; y < 2; y++) {
				for (int z = 0; z < 2; z++) {
					xyRotate(vertex[x][y][z], Math.sin(xyR), Math.cos(xyR));
					xzRotate(vertex[x][y][z], Math.sin(xzR), Math.cos(xzR));
					yzRotate(vertex[x][y][z], Math.sin(yzR), Math.cos(yzR));
				}
			}
		}

		// draw cube edges
		for (int x = 0; x < 2; x++) {
			for (int y = 0; y < 2; y++) {
				g.setColor(Color.red);
				drawEdge(vertex[x][y][0][0], vertex[x][y][0][1], vertex[x][y][1][0], vertex[x][y][1][1], g);
				g.setColor(Color.blue);
				drawEdge(vertex[x][0][y][0], vertex[x][0][y][1], vertex[x][1][y][0], vertex[x][1][y][1], g);
				g.setColor(Color.green);
				drawEdge(vertex[0][x][y][0], vertex[0][x][y][1], vertex[1][x][y][0], vertex[1][x][y][1], g);
			}
		}

		// draw cube vertices
		for (int x = 0; x < 2; x++) {
			for (int y = 0; y < 2; y++) {
				for (int z = 0; z < 2; z++) {
					drawVertex(vertex[x][y][z][0], vertex[x][y][z][1], g);
				}
			}
		}
		g.setColor(Color.black);
		g.fillRect(0, 0, 250, 60);
		g.setColor(Color.white);
		g.drawString("FPS: " + fpsc.getFPS(), 5, 10);
		g.drawString("Renderer: " + getRenderMethod(), 5, 25);
		g.drawString("Sync: " + getSyncMethod(), 5, 40);
		g.drawString("Backend: " + getBackend(), 5, 55);
		fpsc.callFPS();
	}

	// apply plane rotation to 3D point, only 2 coordinates are affected
	final void xyRotate(double p[], double sin, double cos) {
		double temp;
		temp = cos * p[0] + sin * p[1];
		p[1] = -sin * p[0] + cos * p[1];
		p[0] = temp;
	}

	final void xzRotate(double p[], double sin, double cos) {
		double temp;
		temp = cos * p[0] + sin * p[2];
		p[2] = -sin * p[0] + cos * p[2];
		p[0] = temp;
	}

	final void yzRotate(double p[], double sin, double cos) {
		double temp;
		temp = cos * p[1] + sin * p[2];
		p[2] = -sin * p[1] + cos * p[2];
		p[1] = temp;
	}

	final void drawEdge(double x1, double y1, double x2, double y2, Graphics g) {
		g.drawLine((int) (x1 * SCALE) + OFFSET, (int) (-y1 * SCALE) + OFFSET, (int) (x2 * SCALE) + OFFSET, (int) (-y2 * SCALE) + OFFSET);
	}

	final void drawVertex(double x, double y, Graphics g) {
		g.setColor(Color.yellow);
		g.fillOval((int) (SCALE * x) + OFFSET - DIAMETER / 2, (int) (SCALE * (-y)) + OFFSET - DIAMETER / 2, DIAMETER, DIAMETER);

		g.setColor(Color.black);
		g.drawOval((int) (SCALE * x) + OFFSET - DIAMETER / 2, (int) (SCALE * (-y)) + OFFSET - DIAMETER / 2, DIAMETER, DIAMETER);
	}

	@Override
	public void start() {
		this.fpsc.start();
		super.start();
	}

	public static void main(String[] args) {
		final JFrame jfr = new JFrame("SmoothCanvas: Spinning Cube");
		jfr.setBackground(Color.black);
		jfr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jfr.setBounds(0, 0, 720, 720);
		jfr.setLayout(new BorderLayout(0, 0));
		final SmoothCanvasTri tri = (SmoothCanvasTri) new SmoothCanvasTri();
		jfr.add(tri, BorderLayout.CENTER);
		jfr.setVisible(true);
		Swing.center(jfr);
		tri.start();
	}
}
